#include "DbPart.h"
#include "connectpool.h"
#include <sstream>
#include <vector>
#include "Game.h"
#include "Logic.h"
#include <iomanip>

CDbPart::CDbPart():m_dbHandler(NULL)
{
}

CDbPart::~CDbPart()
{
}

bool CDbPart::getOldestGameTecordItem(const std::string& tname, _u64_& seq, int& nodataflag)
{
	ostringstream ossSQL;
	ossSQL << "select seq from " << tname << " order by seq limit 1";

	nodataflag = 0;
	if (m_dbHandler->m_pMysqlConn->GetConnect() == NULL)
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("getOldestGameTecordItem Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}
	if (m_dbHandler->m_pStore->Query(ossSQL.str()))
	{
		unsigned long count = m_dbHandler->m_pStore->RowCount();
		if (count == 0)
		{
			nodataflag = 1;
			log_debug("getOldestGameTecordItem count=0");
			return true;
		}

		seq = m_dbHandler->m_pStore->GetItemLongLong(0, "seq");

		log_debug("getOldestGameTecordItem from db SQL=%s", ossSQL.str().c_str());
		return true;
	}
	else
	{
		log_error("Sql execution failed SQL=%s \n", ossSQL.str().c_str());
	}
	return false;
}
bool CDbPart::getYmInfo(const std::string& tname, const std::string& ym, unsigned int& seq, int& nodataflag)
{
	ostringstream ossSQL;
	ossSQL << "select seq from "<< tname << " where ym = \'"<< ym <<"\'";

	nodataflag = 0;
	if (m_dbHandler->m_pMysqlConn->GetConnect() == NULL)
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("getAsset Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}
	if (m_dbHandler->m_pStore->Query(ossSQL.str()))
	{
		unsigned long count = m_dbHandler->m_pStore->RowCount();
		if (count == 0)
		{
			nodataflag = 1;
			log_error("getYmInfo count=0");
			return false;
		}

		seq = m_dbHandler->m_pStore->GetItemLong(0, "seq");
		log_debug("getYmInfo from db SQL=%s, count=%d,seq= %d", ossSQL.str().c_str(), count, seq);

		return true;
	}
	else
	{
		log_error("Sql execution failed SQL=%s \n", ossSQL.str().c_str());
	}
	return false;
}

bool CDbPart::addYearMonth(const std::string& tname, const std::string& ym, const unsigned int seq)
{
	ostringstream ossSQL;
	ossSQL << "insert into " << tname <<"(ym, seq) values(\'" << ym << "\',"<< seq << ") ON DUPLICATE KEY UPDATE seq=seq";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("addYearMonth Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

bool CDbPart::getFirstMonth(const std::string& tname, std::pair<std::string, unsigned int>& month, int& nodataflag)
{
	ostringstream ossSQL;
	ossSQL << "select ym,seq from " << tname << " order by seq limit 1";

	nodataflag = 0;
	if (m_dbHandler->m_pMysqlConn->GetConnect() == NULL)
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("getAsset Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}
	if (m_dbHandler->m_pStore->Query(ossSQL.str()))
	{
		unsigned long count = m_dbHandler->m_pStore->RowCount();
		if (count == 0)
		{
			nodataflag = 1;
			log_error("ERROR getFirstMonth count=0");
			return false;
		}

		month.first = m_dbHandler->m_pStore->GetItemString(0, "ym");
		month.second = m_dbHandler->m_pStore->GetItemLong(0, "seq");
		
		log_debug("getFirstMonth from db SQL=%s, ym-%s,seq= %u", ossSQL.str().c_str(), month.first.c_str(), month.second);
		return true;
	}	
	else
	{
		log_error("Sql execution failed SQL=%s \n", ossSQL.str().c_str());
	}

	return false;
}

bool CDbPart::createRecordTable(const std::string& tname) 
{
	ostringstream ossSQL;
	ossSQL << "CREATE TABLE IF NOT EXISTS `"<< tname<< "`(`seq` BIGINT UNSIGNED NOT NULL auto_increment,`uid` INT UNSIGNED NOT NULL DEFAULT 0,`useq` INT UNSIGNED NOT NULL DEFAULT 0,`roundid` VARCHAR(30) NOT NULL DEFAULT \'\', `bet` BIGINT NOT NULL DEFAULT 0, `betact` INT NOT NULL DEFAULT 0, `win` BIGINT NOT NULL DEFAULT 0, `winact` INT NOT NULL DEFAULT 0, `daybetamount` BIGINT NOT NULL DEFAULT 0, `daywinamount` BIGINT NOT NULL DEFAULT 0,`tt` BIGINT UNSIGNED NOT NULL DEFAULT 0, `dayfirstflag` INT NOT NULL DEFAULT 0, `detail` BLOB, PRIMARY KEY (`seq`), INDEX idx_uid (`uid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("createRecordTable Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	log_debug("createRecordTable ok,%s", tname.c_str());
	return true;
}

bool CDbPart::addRecord(const std::string& tname, const unsigned int uid, const unsigned int useq, const std::string& roundid, const int64 bet, const int betact,  const int64 win, const int winact, const int64 betamount
		,const int64 winamount, const _u64_ tt, const int dayfirstflag, const std::string& detail)
{
	std::stringstream ss;
    ss << std::hex << std::uppercase << std::setfill('0');
	for (std::string::const_iterator it = detail.begin(); it != detail.end(); ++it)
	{
		ss << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(*it));
	}

	ostringstream ossSQL;
	ossSQL << "insert into " << tname << "(uid, useq, roundid, bet, betact, win, winact, daybetamount, daywinamount, tt, dayfirstflag, detail) values(" << uid << "," << useq << ",\'" << roundid << "\'," << bet << "," << betact << "," << win << "," << winact << "," << betamount << "," << winamount << "," << tt << ","<< dayfirstflag <<",x\'" << ss.str() << "\')";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("addRecord Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

_u64_ CDbPart::getLastSqlId(void)
{
	return m_dbHandler->m_pStore->GetIncreaseID();
}

bool CDbPart::getUserRecordCount(const std::string& tname, const unsigned int uid, const unsigned int mod, unsigned int& count, int& nodataflag)
{
	ostringstream ossSQL;
	ossSQL << "select count from " << tname << " where uid = " << uid;

	if (m_dbHandler->m_pMysqlConn->GetConnect() == NULL)
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("getUserRecordCount Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}
	if (m_dbHandler->m_pStore->Query(ossSQL.str()))
	{
		unsigned long num = m_dbHandler->m_pStore->RowCount();
		if (num == 0)
		{
			count = 0;
			nodataflag = 1;

			log_debug("getUserRecordCount uid=%u count=0", uid);
			return true;
		}

		count = m_dbHandler->m_pStore->GetItemLong(0, "count");
		nodataflag = 0;

		log_debug("getUserRecordCount from db SQL=%s, count=%u,uid= %u", ossSQL.str().c_str(), count, uid);

		return true;
	}
	else
	{
		log_error("Sql execution failed SQL=%s \n", ossSQL.str().c_str());
	}
	return false;
}

bool CDbPart::addUserRecordCount(const std::string& tname, const unsigned int uid, const unsigned int mod, const unsigned int delt)
{
	ostringstream ossSQL;
	ossSQL << "update "<< tname << " set count = count+" << delt << " where uid =" << uid;

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("addUserRecordCount Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

bool CDbPart::insertAndaddUserRecordCount(const std::string& tname, const unsigned int uid, const unsigned int mod, const unsigned int delt, const int timezoneinmin)
{
	ostringstream ossSQL;
	ossSQL << "insert into " << tname << "(uid, count, timezoneinmin) values("<<uid<<","<<delt << ","<< timezoneinmin <<") ON DUPLICATE KEY UPDATE count = count+" << delt;

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("insertAndaddUserRecordCount Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

bool CDbPart:: createGameRecordCountTable(const std::string& tname)
{ 
	ostringstream ossSQL;
	ossSQL << "CREATE TABLE IF NOT EXISTS `"<< tname<< "` (`uid` int unsigned NOT NULL DEFAULT 0,`count` int unsigned NOT NULL DEFAULT 0,`timezoneinmin` int NOT NULL DEFAULT 0, PRIMARY KEY (`uid`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("createGameRecordCountTable Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

bool CDbPart::createMonthListTable(const std::string& tname)
{
	ostringstream ossSQL;
	ossSQL << "CREATE TABLE IF NOT EXISTS `"<< tname<< "` (`ym` varchar(10) NOT NULL DEFAULT \'\',`seq` int unsigned NOT NULL,`delflag` int NOT NULL DEFAULT 0 COMMENT \'月数据删除标记\',PRIMARY KEY (`ym`) , UNIQUE KEY `idx_seq` (`seq`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("createMonthListTable Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}

bool CDbPart::getAgencyArea(const unsigned int agencyid, std::string& area, int& nodataflag)
{
	ostringstream ossSQL;
	ossSQL << "select country from agency where id = " << agencyid <<" limit 1";

	nodataflag = 0;
	if (m_dbHandler->m_pMysqlConn->GetConnect() == NULL)
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("getAsset Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	if (m_dbHandler->m_pStore->Query(ossSQL.str()))
	{
		unsigned long count = m_dbHandler->m_pStore->RowCount();
		if (count == 0)
		{
			nodataflag = 1;
			return true;
		}

		area = m_dbHandler->m_pStore->GetItemString(0, "country");
		log_debug("getAgencyArea  from db SQL=%s, count=%d,area= %s", ossSQL.str().c_str(), count, area.c_str());

		return true;
	}
	else
	{
		log_error("Sql execution failed SQL=%s \n", ossSQL.str().c_str());
	}
	return false;
}

bool CDbPart::addTableRecord(const std::string& tname, const unsigned int game, const unsigned int ym, const unsigned int uidmod, const _u64_ rt)
{
	ostringstream ossSQL;
	ossSQL << "insert into gamerecord_table_record(tname, game, ym, uidmod, rt) values(\'" << tname << "\',"<< game <<","<< ym <<"," << uidmod << "," << rt << ") ON DUPLICATE KEY UPDATE uidmod=uidmod";

	if (!m_dbHandler->UpdateSql(ossSQL.str().c_str()))
	{
		m_dbHandler->m_strError = m_dbHandler->m_pMysqlConn->What();
		log_error("addTableRecord Error: %s\r Sql=%s \n", m_dbHandler->m_pMysqlConn->What().c_str(), ossSQL.str().c_str());

		return false;
	}

	return true;
}